﻿// HomeSystemEditor.xaml.cs
//
// Copyright (c) 2007 Mike Strobel
//
// This source code is subject to the terms of the Microsoft Reciprocal License (Ms-RL).
// For details, see <http://www.opensource.org/licenses/ms-rl.html>.
//
// All other rights reserved.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;

using Supremacy.Entities;
using Supremacy.UI;
using Supremacy.Universe;

namespace Supremacy.Editor
{
    /// <summary>
    /// Interaction logic for HomeSystemEditor.xaml
    /// </summary>
    public partial class HomeSystemEditor
    {
        #region Fields
        private readonly List<PlanetSize?> _planetSizes;
        private readonly List<PlanetType?> _planetTypes;
        private readonly ICollectionView _races;
        private readonly List<StarType?> _starTypes;

        private Selector _starTypesList;
        private Panel _planetConfigPanel;
        #endregion

        #region Constructors
        public HomeSystemEditor()
        {
            InitializeComponent();

            _starTypes = new List<StarType?>();
            foreach (StarType starType in Enum.GetValues(typeof(StarType)))
            {
                if (starType.SupportsPlanets())
                    _starTypes.Add(starType);
            }

            _planetTypes = new List<PlanetType?>();
            foreach (PlanetType planetType in Enum.GetValues(typeof(PlanetType)))
                _planetTypes.Add(planetType);

            _planetSizes = new List<PlanetSize?>();
            foreach (PlanetSize planetSize in Enum.GetValues(typeof(PlanetSize)))
            {
                if (planetSize != PlanetSize.NoWorld)
                    _planetSizes.Add(planetSize);
            }

            //_races = new List<Race>(EditorContext.Races);
            //_races.Sort(delegate(Race x, Race y) { return x.PluralName.CompareTo(y.PluralName); });

            _races = new ListCollectionView(EditorContext.Races);
            _races.SortDescriptions.Add(new SortDescription("PluralName", ListSortDirection.Ascending));

            CommandBindings.Add(new CommandBinding(ComponentCommands.MoveLeft));
            CommandBindings.Add(new CommandBinding(ComponentCommands.MoveRight));
            CommandBindings.Add(new CommandBinding(ApplicationCommands.Delete));
            CommandBindings.Add(new CommandBinding(ApplicationCommands.New));

            foreach (CommandBinding commandBinding in CommandBindings)
            {
                commandBinding.CanExecute += CanExecute;
                commandBinding.PreviewExecuted += Executed;
            }

            Loaded += this.HomeSystemEditor_Loaded;
            Unloaded += this.HomeSystemEditor_Unloaded;
            DataContextChanged += this.HomeSystemEditor_DataContextChanged;
        }

        private void HomeSystemEditor_Unloaded(object sender, RoutedEventArgs e)
        {
            EditorContext.AddingNew -= this.EditorWindow_AddingNew;
        }

        private void EditorWindow_AddingNew(object sender, AddingNewEventArgs e)
        {
            if (e.NewObject is Race)
                RefreshData();
        }
        #endregion

        #region Methods
        internal void RefreshData()
        {
            _races.Refresh();
        }

        private void AutoPlanetNameCheckBox_Changed(object sender, RoutedEventArgs e)
        {
            CheckBox source = sender as CheckBox;
            if (source != null)
            {
                Selector planetsList = ((Control)Content).Template.FindName("PlanetsList", ((Control)Content)) as Selector;
                if ((planetsList != null) && (planetsList.SelectedItem is PlanetDescriptor))
                {
                    PlanetDescriptor planet = (PlanetDescriptor)planetsList.SelectedItem;
                    if (source.IsChecked.Value)
                    {
                        planet.Name = null;
                    }
                    else if (!planet.IsNameDefined)
                    {
                        planet.Name = String.Empty;
                    }
                    if (_planetConfigPanel != null)
                        _planetConfigPanel.Visibility = Visibility.Visible;
                }
            }
        }

        private void AutoPlanetSizeCheckBox_Changed(object sender, RoutedEventArgs e)
        {
            CheckBox source = sender as CheckBox;
            if (source != null)
            {
                Selector planetsList = ((Control)Content).Template.FindName("PlanetsList", ((Control)Content)) as Selector;
                if ((planetsList != null) && (planetsList.SelectedItem is PlanetDescriptor))
                {
                    PlanetDescriptor planet = (PlanetDescriptor)planetsList.SelectedItem;
                    if (source.IsChecked.Value)
                    {
                        planet.Size = null;
                    }
                    else if (!planet.IsSizeDefined)
                    {
                        planet.Size = _planetSizes[0];
                    }
                }
            }
        }

        private void AutoPlanetTypeCheckBox_Changed(object sender, RoutedEventArgs e)
        {
            CheckBox source = sender as CheckBox;
            if (source != null)
            {
                Selector planetsList = ((Control)Content).Template.FindName("PlanetsList", ((Control)Content)) as Selector;
                if ((planetsList != null) && (planetsList.SelectedItem is PlanetDescriptor))
                {
                    PlanetDescriptor planet = (PlanetDescriptor)planetsList.SelectedItem;
                    if (source.IsChecked.Value)
                    {
                        planet.Type = null;
                    }
                    else if (!planet.IsTypeDefined)
                    {
                        planet.Type = _planetTypes[0];
                    }
                }
            }
        }

        private void AutoStarTypeCheckBox_Changed(object sender, RoutedEventArgs e)
        {
            CheckBox source = sender as CheckBox;
            if (source != null)
            {
                StarSystemDescriptor system = DataContext as StarSystemDescriptor;
                if (system != null)
                {
                    if (source.IsChecked.Value)
                    {
                        system.StarType = null;
                        if (_starTypesList != null)
                            _starTypesList.IsEnabled = false;
                    }
                    else
                    {
                        if (!system.IsStarTypeDefined)
                            system.StarType = _starTypes[0];
                        if (_starTypesList != null)
                            _starTypesList.IsEnabled = true;
                    }
                }
            }
        }

        private void CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            PlanetDescriptor planet = e.Parameter as PlanetDescriptor;
            StarSystemDescriptor system = this.DataContext as StarSystemDescriptor;
            
            if ((e.Parameter != null) && (planet == null))
            {
                return;
            }
            if (system == null)
            {
                e.CanExecute = false;
                return;
            }

            if (e.Command == ComponentCommands.MoveLeft)
            {
                e.CanExecute = ((planet != null)
                    && system.Planets.Contains(planet)
                        && (system.Planets.IndexOf(planet) < (system.Planets.Count - 1)));
                e.Handled = true;
            }
            else if (e.Command == ComponentCommands.MoveRight)
            {
                e.CanExecute = ((planet != null) && (system.Planets.IndexOf(planet) > 0));
                e.Handled = true;
            }
            else if (e.Command == ApplicationCommands.Delete)
            {
                e.CanExecute = ((planet != null) && (system.Planets.Contains(planet)));
                e.Handled = true;
            }
            else if (e.Command == ApplicationCommands.New)
            {
                int totalPlanets = 0;
                foreach (PlanetDescriptor otherPlanet in system.Planets)
                    totalPlanets += otherPlanet.MinNumberOfPlanets;
                e.CanExecute = (totalPlanets < StarSystem.MaxPlanetsPerSystem);
                e.Handled = true;
            }
            else
            {
                e.CanExecute = false;
            }
        }

        private void Executed(object sender, ExecutedRoutedEventArgs e)
        {
            PlanetDescriptor planet = e.Parameter as PlanetDescriptor;
            StarSystemDescriptor system = this.DataContext as StarSystemDescriptor;

            if (((e.Parameter != null) && (planet == null)) || (system == null))
            {
                return;
            }

            if (e.Command == ApplicationCommands.New)
            {
                PlanetDescriptor newPlanet = new PlanetDescriptor();
                system.Planets.Add(newPlanet);
                CollectionViewSource.GetDefaultView(system.Planets).MoveCurrentTo(newPlanet);
                e.Handled = true;
                UpdateSpinners();
                return;
            }
            if (planet != null)
            {
                if (e.Command == ComponentCommands.MoveLeft)
                {
                    int currentIndex = system.Planets.IndexOf(planet);
                    if ((currentIndex != -1) && (currentIndex < (system.Planets.Count - 1)))
                    {
                        system.Planets.RemoveAt(currentIndex);
                        system.Planets.Insert(currentIndex + 1, planet);
                        CollectionViewSource.GetDefaultView(system.Planets).MoveCurrentTo(planet);
                    }
                    e.Handled = true;
                    return;
                }
                if (e.Command == ComponentCommands.MoveRight)
                {
                    int currentIndex = system.Planets.IndexOf(planet);
                    if (currentIndex > 0)
                    {
                        system.Planets.RemoveAt(currentIndex);
                        system.Planets.Insert(currentIndex - 1, planet);
                        CollectionViewSource.GetDefaultView(system.Planets).MoveCurrentTo(planet);
                    }
                    e.Handled = true;
                    return;
                }
                if (e.Command == ApplicationCommands.Delete)
                {
                    system.Planets.Remove(planet);
                    e.Handled = true;
                    UpdateSpinners();
                    return;
                }
            }
        }

        private void UpdateSpinners()
        {
            NumericUpDown maxPlanetsSpinner = ((Control)Content).Template.FindName("MaxNumberOfPlanetsSpinner", ((Control)Content)) as NumericUpDown;
            NumericUpDown minPlanetsSpinner = ((Control)Content).Template.FindName("MinNumberOfPlanetsSpinner", ((Control)Content)) as NumericUpDown;
            if ((maxPlanetsSpinner != null) && (minPlanetsSpinner != null))
            {
                minPlanetsSpinner.Minimum = 0;
                minPlanetsSpinner.Maximum = StarSystem.MaxPlanetsPerSystem;
                maxPlanetsSpinner.Minimum = Math.Min(StarSystem.MaxPlanetsPerSystem, Math.Max(2, minPlanetsSpinner.Value));
                maxPlanetsSpinner.Maximum = StarSystem.MaxPlanetsPerSystem;   
            }
        }

        private void HomeSystemEditor_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            StarSystemDescriptor system = e.OldValue as StarSystemDescriptor;
            if (system != null)
                CollectionViewSource.GetDefaultView(system.Planets).MoveCurrentToPosition(-1);
            Update();
        }

        private void HomeSystemEditor_Loaded(object sender, RoutedEventArgs e)
        {
            var editorContext = this.EditorContext;
            if (editorContext != null)
                editorContext.AddingNew += this.EditorWindow_AddingNew;
            Update();
        }

        private void PlanetRadioButton_Checked(object sender, RoutedEventArgs e)
        {
            Selector planetsList = ((Control)Content).Template.FindName("PlanetsList", ((Control)Content)) as Selector;
            NumericUpDown maxPlanetsSpinner = ((Control)Content).Template.FindName("MaxNumberOfPlanetsSpinner", ((Control)Content)) as NumericUpDown;
            NumericUpDown minPlanetsSpinner = ((Control)Content).Template.FindName("MinNumberOfPlanetsSpinner", ((Control)Content)) as NumericUpDown;
            RadioButton source = sender as RadioButton;

            if ((planetsList == null) || (source == null))
                return;

            PlanetDescriptor planet = planetsList.SelectedItem as PlanetDescriptor;
            if (planet != null)
            {
                if (source.Name == "SinglePlanetRadioButton")
                {
                    if ((maxPlanetsSpinner != null) && (minPlanetsSpinner != null))
                    {
                        BindingOperations.ClearBinding(minPlanetsSpinner, NumericUpDown.ValueProperty);
                        BindingOperations.ClearBinding(maxPlanetsSpinner, NumericUpDown.ValueProperty);
                    }
                    planet.MinNumberOfPlanets = 1;
                    planet.MaxNumberOfPlanets = 1;
                }
                else if (source.Name == "MultiPlanetRadioButton")
                {
                    if (planet.MaxNumberOfPlanets == 1)
                    {
                        planet.MaxNumberOfPlanets = (planet.MinNumberOfPlanets > 1)
                            ? planet.MinNumberOfPlanets
                            : StarSystem.MaxPlanetsPerSystem;
                    }
                    if ((maxPlanetsSpinner != null) && (minPlanetsSpinner != null))
                    {
                        BindingOperations.SetBinding(minPlanetsSpinner, NumericUpDown.ValueProperty, new Binding("MinNumberOfPlanets"));
                        BindingOperations.SetBinding(maxPlanetsSpinner, NumericUpDown.ValueProperty, new Binding("MaxNumberOfPlanets"));
                    }
                }
            }
        }

        private void PlanetSizeList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Selector planetSizeList = sender as Selector;
            if ((planetSizeList != null) && (planetSizeList.SelectedIndex != -1))
            {
                CheckBox autoPlanetSizeCheckBox = ((Control)Content).Template.FindName("AutoPlanetSizeCheckBox", ((Control)Content)) as CheckBox;
                if (autoPlanetSizeCheckBox != null)
                    autoPlanetSizeCheckBox.IsChecked = false;
            }
        }

        private void PlanetsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Selector planetsList = sender as Selector;
            if (planetsList != null)
            {
                PlanetDescriptor planet = planetsList.SelectedItem as PlanetDescriptor;
                if (planet != null)
                {
                    CheckBox autoPlanetNameCheckBox = ((Control)Content).Template.FindName("AutoPlanetNameCheckBox", ((Control)Content)) as CheckBox;
                    CheckBox autoPlanetTypeCheckBox = ((Control)Content).Template.FindName("AutoPlanetTypeCheckBox", ((Control)Content)) as CheckBox;
                    CheckBox autoPlanetSizeCheckBox = ((Control)Content).Template.FindName("AutoPlanetSizeCheckBox", ((Control)Content)) as CheckBox;
                    RadioButton radioButton = planet.IsSinglePlanet
                        ? ((Control)Content).Template.FindName("SinglePlanetRadioButton", ((Control)Content)) as RadioButton
                        : ((Control)Content).Template.FindName("MultiPlanetRadioButton", ((Control)Content)) as RadioButton;
                    if (autoPlanetNameCheckBox != null)
                        autoPlanetNameCheckBox.IsChecked = !planet.IsNameDefined;
                    if (autoPlanetTypeCheckBox != null)
                        autoPlanetTypeCheckBox.IsChecked = !planet.IsTypeDefined;
                    if (autoPlanetSizeCheckBox != null)
                        autoPlanetSizeCheckBox.IsChecked = !planet.IsSizeDefined;
                    if (radioButton != null)
                        radioButton.IsChecked = true;
                    if (_planetConfigPanel != null)
                        _planetConfigPanel.Visibility = Visibility.Visible;
                }
                else
                {
                    if (_planetConfigPanel != null)
                        _planetConfigPanel.Visibility = Visibility.Collapsed;
                }
            }
        }

        private void PlanetTypesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Selector planetTypesList = sender as Selector;
            if ((planetTypesList != null) && (planetTypesList.SelectedIndex != -1))
            {
                CheckBox autoPlanetTypeCheckBox = ((Control)Content).Template.FindName("AutoPlanetTypeCheckBox", ((Control)Content)) as CheckBox;
                if (autoPlanetTypeCheckBox != null)
                {
                    autoPlanetTypeCheckBox.IsChecked = false;
                }
            }
        }

        private void Update()
        {
            RefreshData();

            if (IsLoaded)
            {
                StarSystemDescriptor system = DataContext as StarSystemDescriptor;

                _planetConfigPanel = ((Control)Content).Template.FindName("PlanetConfigPanel", ((Control)Content)) as Panel;
                _starTypesList = ((Control)Content).Template.FindName("StarTypesList", ((Control)Content)) as Selector;

                if (_starTypesList != null)
                {
                    _starTypesList.ItemsSource = _starTypes;
                }

                Selector planetsList = ((Control)Content).Template.FindName("PlanetsList", ((Control)Content)) as Selector;
                if (planetsList != null)
                {
                    if (system != null)
                    {
                        CollectionViewSource.GetDefaultView(system.Planets).MoveCurrentToPosition(-1);
                    }
                    else
                    {
                        planetsList.Items.MoveCurrentToPosition(-1);
                    }
                    if (_planetConfigPanel != null)
                    {
                        _planetConfigPanel.Visibility = (planetsList.SelectedItem is PlanetDescriptor)
                            ? Visibility.Visible
                            : Visibility.Collapsed;
                    }
                }

                Selector inhabitantsList = ((Control)Content).Template.FindName("InhabitantsList", ((Control)Content)) as Selector;
                if (inhabitantsList != null)
                {
                    object selectedValue = inhabitantsList.SelectedValue;
                    inhabitantsList.ItemsSource = _races;
                    inhabitantsList.SelectedValue = selectedValue;
                }

                Selector planetTypesList = ((Control)Content).Template.FindName("PlanetTypesList", ((Control)Content)) as Selector;
                if (planetTypesList != null)
                {
                    planetTypesList.ItemsSource = _planetTypes;
                }

                Selector planetSizeList = ((Control)Content).Template.FindName("PlanetSizeList", ((Control)Content)) as Selector;
                if (planetSizeList != null)
                {
                    planetSizeList.ItemsSource = _planetSizes;
                }

                if (system != null)
                {
                    CheckBox autoStarTypeCheckBox = ((Control)Content).Template.FindName("AutoStarTypeCheckBox", ((Control)Content)) as CheckBox;
                    if (autoStarTypeCheckBox != null)
                        autoStarTypeCheckBox.IsChecked = !system.IsStarTypeDefined;
                }
            }
        }
        #endregion

        private void NumberOfPlanetsSpinner_ValueChanged(object sender, RoutedPropertyChangedEventArgs<decimal> e)
        {
            UpdateSpinners();
        }
    }
}